/******************************************************************************
*
* This file is part of FreeTrack (http://code.google.com/p/qtfreetrack).
* BY Willy Gardiol (willy@gardiol.org)
*
* FreeTrack is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTrack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/

#include "configwidget.h"
#include "filenavigator.h"
#include "oauthmanager.h"
#include "configfile.h"

#include "fttabwidget.h"
#include "ftwidgetlist.h"
#include "fthelpwidget.h"
#include "ftpushbutton.h"

ConfigWidget* conf = NULL;
ConfigWidget::ConfigWidget(QWidget *parent) :
    FreeTrackWidget(parent)
{
    conf = this;
    initial_orientation = automaticOrientation;

    tabs = new FTTabWidget();

    // Create the general tab
    tab_general = new QWidget();
    // Create the autosave checkbox
    autosave = new QCheckBox( tr("Live Track autosave") );
    autosave->setChecked(true);
    connect( autosave, SIGNAL(clicked(bool)),
                 this, SIGNAL(autosaveChange(bool)));
    // Create the save position checkbox
    saveposition = new QCheckBox( tr("Save tracking table position") );
    saveposition->setChecked(true);
    connect( saveposition, SIGNAL(clicked(bool)),
                 this, SIGNAL(savepositionChange(bool)));
    // Create the save orientation checkbox
    saveorientation = new QCheckBox( tr("Save screen orientation") );
    saveorientation->setChecked(true);
    connect( saveorientation, SIGNAL(clicked(bool)),
                 this, SIGNAL(saveorientationChange(bool)));
    // Create the confirm internet checkbox
    confirminternet = new QCheckBox( tr("Confirm internet access") );
    confirminternet->setChecked(true);
    connect( confirminternet, SIGNAL(clicked()),
                 this, SLOT(setModified()) );
    // Create the prepache maps checkbox
    precachemaps = new QCheckBox( tr("Precache maps on load") );
    precachemaps->setChecked(true);
    connect( precachemaps, SIGNAL(clicked()),
                 this, SLOT(setModified()) );
    // Create the calc speed checkbox
    calc_speed = new QCheckBox( tr("Calculate missing speeds") );
    calc_speed->setChecked(true);
    connect( calc_speed, SIGNAL(clicked()),
                 this, SLOT(setModified()) );
    // Create the alwayson checkbox
    always_on = new QCheckBox( tr("Keep backlight always on") );
    always_on->setChecked(false);
    connect( always_on, SIGNAL(clicked(bool)),
                 this, SLOT(alwaysOn(bool)) );
    // Altitude correction widgets
    altitude_group = new QGroupBox( tr("Altitude correction (m)") );
    QHBoxLayout* agrid = new QHBoxLayout(altitude_group);
    altitude = new QLineEdit();
    agrid->addWidget( altitude );
    connect( altitude, SIGNAL(textChanged(QString)),
                 this, SLOT(altitudeCorrectionChanged(QString)));
    altitude_correction = 0;

    general_help = new FTHelpWidget(tr(
            "<center|b>General Configuration</center>"\
            "<justify>These options allows you to customize the behaviour of FreeTrack</justify>"\
            "<center|b>Live Track Autosave</center>"\
            "<justify>This option will enable the autosave feature of the Live Track. When autosave "\
            "is active, you will not have to save the track yourself. FreeTrack will take care of that "\
            "in a way that will optimize battery usage while preventing you to lose even only one point. "\
            "You should really use autosave all the time.</justify>"\
            "<center|b>Save table position</center>"\
            "<justify>This option will store the last position on the tracking table "\
            "when you close FreeTrack. In this way, when you open FreeTrack again it will "\
            "be already centerd where you left it.</justify>"\
            "<center|b>Save screen orientation</center>"\
            "<justify>This option will store the current screen orientation (landscape, portrait or automatic) "\
            "so that upon next FreeTrack execution it will automatically rotate according to your preference."\
            "</justify>"\
            "<center|b>Confirm Internet Access</center>"\
            "<justify>When this option is enabled, FreeTrack will always ask for confirmation before "\
            "attempting any internet connection. Enable this option if you do not have a flat data connection "\
            "plan. (note: data connections will be done ONLY for export to www.gobreadcrumbs.com)</justify>"\
            "<center|b>Precache maps on load</center>"\
            "<justify>Maps are cached on the phone, to speed up map drawing. If this option is selected "\
            "when you load a new map it will be cached immediately. You can always clear the cache and "\
            "recreate it from the map configuration dialog. Keep this enabled.</justify>"\
            "<center|b>Calculate speeds</center>"\
            "<justify>On certain GPS devices or under specific circumstances, the GPS does not "\
            "return a valid speed. This option lets FreeTrack calculate an 'averaged' speed when the speed "\
            "is not available from the GPS. You should enable this only if you care.</justify>"\
            "<center|b>Keep backlight on</center>"\
            "<justify>This option will force your phone screen to be always on. This will prevent "\
            "the screensaver to start, the screen light to turn off, and the screen lock to engage. "\
            "Please note that this feature is only available from OVI store due to Nokia restictions.</justify>"\
            "<center|b>Altitude Calibration</center>"\
            "<justify>Since some GPS devices always report the altitude biased by an offset, this "\
            "option lets you add a fixed correction factor (in meters) to the altitude.</justify>"
            ));


    // Create the breadcrumbs widgets
    breadcrumbs = new QGroupBox( tr("www.gobreadcrumbs.com") );
    QVBoxLayout* vgrid = new QVBoxLayout(breadcrumbs);
    breadcrumbs_help = new FTHelpWidget( tr(
        "<center|b>GoBreadcrumbs setup</center>"\
        "<justify>First you need to create an account on www.gobreadcrumbs.com with your "\
        "web browser, then you can start the authorization process. </justify>"\
        "<justify>Once you have an account, tap on the 'Authorize' button, after a little bit "\
        "you will be prompted to get a PIN: the phone browser will be launched and you will automatically "\
        "go to the GoBreadcrumbs login page. Here insert your login and password, GoBreadcrumbs will ask "\
        "you to authorize FreeTrack. After you accept, you will be given a PIN which you must copy here "\
        "on the 'Set PIN' text area. If the PIN is correct, you will be allowed to use GoBreadcrumb services "\
        "from within FreeTrack.</justify>"\
        "<justify>Once you are authorized, you will not have to repeat this steps again, FreeTrack will "\
        "remember the authorization tokens.</justify>"\
        "<center|i>GoBreadbrumbs is a free service with no direct connection to FreeTrack.</center>"));
    vgrid->addWidget( breadcrumbs_help );
    QHBoxLayout* grid = new QHBoxLayout();
    vgrid->addLayout( grid );
    breadcrumbs_authorize = new FTPushButton( tr("Authorize...") );
    breadcrumbs_setpin = new FTPushButton( tr("Set PIN...") );
    breadcrumbs_setpin->setVisible(false);
    breadcrumbs_pin = new QLineEdit();
    breadcrumbs_pin->setVisible( false );
    grid->addWidget(breadcrumbs_authorize);
    QVBoxLayout* ping = new QVBoxLayout();
    ping->addWidget(breadcrumbs_pin);
    ping->addWidget(breadcrumbs_setpin);
    grid->addLayout(ping);
    breadcrumbs_token = breadcrumbs_tokenSecret = QByteArray();
    connect( breadcrumbs_authorize, SIGNAL(clicked()),
                              this, SLOT( breadcrumbsAuthorize()) ),
    connect( breadcrumbs_setpin, SIGNAL(clicked()),
                           this, SLOT( breadcrumbsSetpin() ));
    breadcrumbs_authorized = false;
    vgrid->addStretch();

    // Build waypoint draw group
    waypoints_group = new QGroupBox( tr("Draw waypoints") );
    QVBoxLayout* bgrid = new QVBoxLayout(waypoints_group);
    waypoints_help = new FTHelpWidget( tr(
       "<center|b>Setup waypoints</center>"\
       "<justify>Here you can activate the waypoints on the map and choose how you want to visualize them: "\
       "you can show a bitmap, the waypoint name or both.</justify>"
            ));
    bgrid->addWidget( waypoints_help );
    draw_waypoints = new QCheckBox( tr("Draw waypoints") );
    draw_waypoints->setChecked(true);
    connect( draw_waypoints, SIGNAL(clicked()),
                 this, SLOT(setModified()) );
    draw_waypoints_icon = new QCheckBox( tr("Draw wyapoint icons") );
    draw_waypoints_icon->setChecked(true);
    connect( draw_waypoints_icon, SIGNAL(clicked()),
                 this, SLOT(setModified()) );
    draw_waypoints_name = new QCheckBox( tr("Draw wyapoint names") );
    draw_waypoints_name->setChecked(true);
    connect( draw_waypoints_name, SIGNAL(clicked()),
                 this, SLOT(setModified()) );
    bgrid->addWidget( draw_waypoints );
    bgrid->addWidget( draw_waypoints_icon );
    bgrid->addWidget( draw_waypoints_name );
    bgrid->addStretch();

    // Setup the configuration now
    LoadConfig();
    // create this AFTER configuration has been read (to set tokens)
    breadcrumbs_oauth = new OauthManager(this, breadcrumbs_token, breadcrumbs_tokenSecret);

    // Make sure modified get reset when configuration changes...
    connect( this, SIGNAL(autosaveChange()),
             this, SLOT(setModified()));
    connect( this, SIGNAL(savepositionChange()),
             this, SLOT(setModified()));
    connect( this, SIGNAL(saveorientationChange()),
             this, SLOT(setModified()));
    connect( this, SIGNAL(breadcrumbsChange()),
             this, SLOT(setModified()) );

    internet_confirmation_stored = internet_confirmation_value = false;


    // The close button
    closeButton = new FTPushButton( tr("Back to FreeTrack") );
    connect( closeButton, SIGNAL(clicked()),
              this, SIGNAL(accept()));

    tabs->addTab( tab_general, tr("General setup") );
    tabs->addTab( waypoints_group, tr("Setup waypoints") );
    tabs->addTab( breadcrumbs, tr("GoBreadcrumbs") );
    tabs->addExtra( closeButton );

#ifdef BUILD_FOR_OVI
    screen_saver = NULL;
#endif
}

ConfigWidget::~ConfigWidget()
{   // Save config if modified
    if ( modified )
        SaveConfig();
#ifdef BUILD_FOR_OVI
    if ( screen_saver != NULL )
        delete screen_saver;
#endif
}

void ConfigWidget::altitudeCorrectionChanged(QString new_alt )
{
    altitude_correction = new_alt.toInt();
}

int ConfigWidget::getAltitudeCorrection()
{
    return altitude_correction;
}

void ConfigWidget::alwaysOn(bool check)
{
#ifdef BUILD_FOR_OVI
    if ( check )
    {
        if ( screen_saver == NULL )
        {
            screen_saver = new QSystemScreenSaver(this);
        }
        screen_saver->setScreenSaverInhibit();
    }
    else
    {
        if ( screen_saver != NULL )
        {
            delete screen_saver;
            screen_saver = NULL;
        }
    }
    setModified();
#else
    QMessageBox::information( this,
                              tr("Sorry"),
                              tr("Due to Nokia restrictions, this function is only available from OVI store!") );
    always_on->setChecked(false);

#endif
}

void ConfigWidget::breadcrumbsSetpin()
{
    QByteArray pin = breadcrumbs_pin->text().toAscii();
    if ( breadcrumbs_oauth->getAccessToken( pin ) )
    {
        breadcrumbs_oauth->getToken( breadcrumbs_token, breadcrumbs_tokenSecret );
        breadcrumbs_authorized = true;
        breadcrumbs_pin->setVisible(false);
        breadcrumbs_setpin->setVisible(false);
        breadcrumbs_authorize->setText( tr("Authorization acquired"));
        breadcrumbs_authorize->setVisible(true);
        QMessageBox::information( this,
                                  tr("www.gobreadcrumbs.com"),
                                  tr("You are now authorized to use GoBreadcrumbs!") );
        emit breadcrumbsChange( true );
    }
    else
    {
        breadcrumbsUnauthorize();
        QMessageBox::information( this,
                                  tr("www.gobreadcrumbs.com"),
                                  tr("Sorry but PIN is invalid!") );
    }
}

void ConfigWidget::breadcrumbsAuthorize()
{
    if ( !breadcrumbs_authorized )
    {
        if ( breadcrumbs_oauth->getRequestToken() )
        {
            breadcrumbs_authorize->setVisible(false);
            breadcrumbs_pin->setVisible(true);
            breadcrumbs_setpin->setVisible(true);
            QMessageBox::information( this,
                                      tr("www.gobreadcrumbs.com"),
                                      tr("Now switch to the browser, login, and note your PIN, you will have to input it here!") );
                        QString url = breadcrumbs_oauth->getAuthUrl();
            QDesktopServices::openUrl(QUrl(url));
        }
        else
        {
            breadcrumbsUnauthorize();
            QMessageBox::information( this,
                                      tr("www.gobreadcrumbs.com"),
                                      tr("Unable to authorize with www.gobreadcrumbs.com!") );
         }
    }
    else
    {
        if ( QMessageBox::question( this,
                                 tr("Remove authorization"),
                                 tr("Remove authorization to use GoBreadcrumbs??"),
                                 QMessageBox::Yes|QMessageBox::No,
                                 QMessageBox::NoButton ) == QMessageBox::Yes )
            breadcrumbsUnauthorize();
    }
}

void ConfigWidget::breadcrumbsUnauthorize()
{
    breadcrumbs_token = "";
    breadcrumbs_authorized = false;
    breadcrumbs_pin->setVisible(false);
    breadcrumbs_setpin->setVisible(false);
    breadcrumbs_authorize->setVisible(true);
    breadcrumbs_authorize->setText( tr("Authorize..."));
    emit breadcrumbsChange(false);
}

bool ConfigWidget::getBreadcrumbsToken(QByteArray& token, QByteArray& tokenSecret)
{
    if ( breadcrumbs_authorized )
    {
        token = breadcrumbs_token;
        tokenSecret = breadcrumbs_tokenSecret;
        return true;
    }
    else
    {
        token = tokenSecret = QByteArray();
        return false;
    }
}

bool ConfigWidget::breadcrumbsAuthorized()
{
    return breadcrumbs_authorized;
}

bool ConfigWidget::getSavePosition()
{
    return saveposition->isChecked();
}

bool ConfigWidget::getPrecacheMaps()
{
    return precachemaps->isChecked();
}

bool ConfigWidget::getInternetAuthorization()
{
    if ( confirminternet->isChecked() )
    {
        if ( internet_confirmation_stored )
            return internet_confirmation_value;

        internet_confirmation_value = QMessageBox::question(0, tr("Confirm Connection?"),
                                     tr("Do you really want to connect to the internet?"),
                                     QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes
                                     ) == QMessageBox::Yes;

        internet_confirmation_stored = true;
        return internet_confirmation_value;
    }
    return true;
}

bool ConfigWidget::getDrawWaypoint()
{
    return draw_waypoints->isChecked();
}

bool ConfigWidget::getDrawWaypointIcon()
{
    return draw_waypoints_icon->isChecked();
}

bool ConfigWidget::getDrawWaypointName()
{
    return draw_waypoints_name->isChecked();
}

bool ConfigWidget::getCalcSpeed()
{
    return calc_speed->isChecked();
}

void ConfigWidget::setInitialPosition(const QPointF& p)
{
    if ( (p != initial_position) && (saveposition->isChecked() ) )
    {
        initial_position = p;
        modified = true;
    }
}

Orientation ConfigWidget::getOrientation()
{
    return initial_orientation;
}

void ConfigWidget::setOrientation( Orientation orient )
{
#ifdef Q_OS_SYMBIAN
    CAknAppUi* appUi = static_cast<CAknAppUi*>( CEikonEnv::Static()->AppUi() );
    switch ( orient )
    {
    case horizontal:
        TRAP_IGNORE(appUi->SetOrientationL( CAknAppUi::EAppUiOrientationLandscape ));
        break;
    case vertical:
        TRAP_IGNORE(appUi->SetOrientationL( CAknAppUi::EAppUiOrientationPortrait ));
        break;
    case automaticOrientation:
        TRAP_IGNORE(appUi->SetOrientationL( CAknAppUi::EAppUiOrientationAutomatic ));
        break;
    }
#else
    // do not do anything, we only support Symbian
#endif
    initial_orientation = orient;
    if ( saveorientation->isChecked() )
        modified = true;
}

bool ConfigWidget::getSaveOrientation()
{
    return saveorientation->isChecked();
}

QPointF ConfigWidget::getInitialPosition()
{
    return initial_position;
}

void ConfigWidget::setModified()
{
    modified = true;
}

QString ConfigWidget::getFilename()
{
    return FileNavigator::default_path() + "/config.txt";
}

bool ConfigWidget::getAutosave()
{
    return autosave->isChecked();
}

void ConfigWidget::LoadConfig()
{
    ConfigFile config( getFilename(), QIODevice::ReadOnly );
    if ( !config.getStatus() )
    {   // Quit if there is no configuration file
         modified = true;
        return;
    }

    // First load and check all the checkboxes...
    QHash<QString, QCheckBox*> checkboxes;
    checkboxes.insert( "autosave", autosave );
    checkboxes.insert( "save_position", saveposition );
    checkboxes.insert( "precache_maps", precachemaps );
    checkboxes.insert( "confirm_internet", confirminternet );
    checkboxes.insert( "draw_waypoints", draw_waypoints );
    checkboxes.insert( "draw_waypoint_icons", draw_waypoints_icon );
    checkboxes.insert( "draw_waypoint_names", draw_waypoints_name );
    checkboxes.insert( "calculate_speed", calc_speed );
    checkboxes.insert( "save_orientation", saveorientation );
#ifdef BUILD_FOR_OVI
    checkboxes.insert( "always_on", always_on );
#endif

    foreach (QString key, checkboxes.keys())
        if ( config.rowExists(key) )
            checkboxes.value(key)->setChecked( config.readRow(key).toLower() == "true" );

    // Load the initial position...
    QRegExp rx("\\s*"REGEXP_NUMBER","REGEXP_NUMBER"\\s*$");
    if ( config.readRow("initial_position", rx ) )
        initial_position = QPointF(((QString)rx.cap(2)).toDouble(),
                                   ((QString)rx.cap(1)).toDouble() );

    // Load breadcrumbs tokens...
    breadcrumbs_token = config.readRow("breadcrumbs_token").toAscii();
    breadcrumbs_tokenSecret = config.readRow("breadcrumbs_tokenSecret").toAscii();
    if ( !breadcrumbs_token.isEmpty() && !breadcrumbs_tokenSecret.isEmpty() )
    {
        breadcrumbs_authorized = true;
        breadcrumbs_authorize->setVisible(true);
        breadcrumbs_authorize->setText( tr("Authorization acquired!") );
        breadcrumbs_setpin->setVisible(false);
        breadcrumbs_pin->setVisible(false);
    }

    // Orientate the phone properly...
    if ( saveorientation->isChecked() )
    {
        QString orient = config.readRow("orientation");
        if ( orient == "portrait" )
            setOrientation(vertical);
        else if ( orient == "landscape" )
            setOrientation(horizontal);
        else
            setOrientation(automaticOrientation);
    }

    // Load altitude correction
    altitude->setText( config.readRow("altitude_correction").toAscii() );
    altitudeCorrectionChanged( altitude->text() );

    modified = false;
}

void ConfigWidget::SaveConfig()
{
    ConfigFile config( getFilename(), QIODevice::WriteOnly );

    config.writeRow("autosave",autosave->isChecked() ? "true" : "false" );
    config.writeRow("save_position", saveposition->isChecked() ? "true" : "false" );
    config.writeRow("initial_position", QString("%1,%2").arg(initial_position.y(),0,'f',7)
                                                        .arg(initial_position.x(),0,'f',7));
    config.writeRow("breadcrumbs_token",breadcrumbs_token.constData());
    config.writeRow("breadcrumbs_tokenSecret",breadcrumbs_tokenSecret.constData());

    config.writeRow("save_orientation", saveorientation->isChecked() ? "true" : "false" );
    if ( saveorientation->isChecked() )
    {
        if ( initial_orientation == vertical )
            config.writeRow("orientation", "portrait" );
        else if ( initial_orientation == horizontal )
            config.writeRow("orientation", "landscape" );
        else
            config.writeRow("orientation", "automatic" );
    }
    config.writeRow("confirm_internet", confirminternet->isChecked() ? "true" : "false" );
    config.writeRow("precache_maps", precachemaps->isChecked() ? "true" : "false" );

#ifdef BUILD_FOR_OVI
    config.writeRow("always_on", always_on->isChecked() ? "true" : "false" );
#endif

    config.writeRow("altitude_correction", altitude->text() );

    config.writeRow("draw_waypoints", draw_waypoints->isChecked() ? "true" : "false" );
    config.writeRow("draw_waypoint_icons", draw_waypoints_icon->isChecked() ? "true" : "false" );
    config.writeRow("draw_waypoint_names", draw_waypoints_name->isChecked() ? "true" : "false" );

    config.writeRow("calculate_speed", calc_speed->isChecked() ? "true" : "false" );

    modified = false;
}

QLayout* ConfigWidget::createVertical()
{
    QVBoxLayout* grid = new QVBoxLayout();
    grid->addWidget( tabs );

    if ( tab_general->layout() != NULL )
        delete tab_general->layout();
    QVBoxLayout* ggrid = new QVBoxLayout();
    ggrid->addWidget( general_help );
    ggrid->addWidget( autosave );
    ggrid->addWidget( saveposition );
    ggrid->addWidget( saveorientation );
    ggrid->addWidget( confirminternet );
    ggrid->addWidget( precachemaps );
    ggrid->addWidget( calc_speed );
    ggrid->addWidget( always_on );
    ggrid->addWidget( altitude_group );
    ggrid->addStretch();
    tab_general->setLayout( ggrid );

    return grid;
}

QLayout* ConfigWidget::createHorizontal()
{
    QVBoxLayout* grid = new QVBoxLayout();
    grid->addWidget( tabs );

    if ( tab_general->layout() != NULL )
        delete tab_general->layout();
    QHBoxLayout* hgrid = new QHBoxLayout();
    QVBoxLayout* ggrid = new QVBoxLayout();
    ggrid->addWidget( autosave );
    ggrid->addWidget( saveposition );
    ggrid->addWidget( saveorientation );
    ggrid->addWidget( confirminternet );
    ggrid->addWidget( precachemaps );
    ggrid->addStretch();
    hgrid->addLayout( ggrid );

    ggrid = new QVBoxLayout();
    ggrid->addWidget( calc_speed );
    ggrid->addWidget( always_on );
    ggrid->addWidget( altitude_group );
    ggrid->addWidget( general_help );
    ggrid->addStretch();
    hgrid->addLayout( ggrid );

    tab_general->setLayout( ggrid );

    return grid;
}
